<?php
/**
 * Created by PhpStorm.
 * User: 牛赞赞
 * Date: 2021/1/26
 * Time: 14:02
 */

namespace App\Game\Core;


class AIRobot extends DdzPoker
{
    /**
     * 分析手牌
     * @param $pokers
     * @return array
     */
    public function allCardType($pokers){
        // 获取火箭和剩余手牌
        $rocketAndLefts = $this->getRocket($pokers);

        // 获取炸弹
        $boom = $this->getBooms($rocketAndLefts['left']);

        // 踢出火箭和炸弹后剩余的手牌
        $left_cards = $this->getLeftCards($boom,$rocketAndLefts['left']);

        // 获取顺子
        $sz_arr = $this->getAllShunZi($left_cards);
        if(!empty($sz_arr)){
            // 如果有顺子，获取去除顺子后的剩余手牌
            $left_cards_without_sz = $this->getLeftCards($sz_arr,$left_cards);
            if(!empty($left_cards_without_sz)){
                // 如果有剩余手牌，继续扩展顺子
                $szAndLefts = $this->extStraightArr($sz_arr,$left_cards_without_sz);
                $sz_arr     = $szAndLefts['new_sz'];
                $left_cards = $szAndLefts['left'];
            }else{
                // 如果全是顺子，没有剩余手牌
                $left_cards = [];
            }
        }

        // 所有三张
        if(!empty($left_cards) && (count($left_cards)>=3)){
            $triples    = $this->getAllTripleArr($left_cards);
            $left_cards = $this->getLeftCards($triples,$left_cards);
        }else{
            $triples = [];
        }

        // 所有对子
        if(!empty($left_cards) && (count($left_cards) >= 2)){
            $double     = $this->getDoubleArr($left_cards);
            $left_cards = $this->getLeftCards($double,$left_cards);
        }else{
            $double = [];
        }

        // 所有单张
        $single = $left_cards;

        $card_types = [
            self::CARD_TYPE_HUOJIAN => $rocketAndLefts['rocket'],
            self::CARD_TYPE_ZHADAN  => $boom,
            self::CARD_TYPE_SHUNZI  => $sz_arr,
            self::CARD_TYPE_SAN     => $triples,
            self::CARD_TYPE_DUI     => $double,
            self::CARD_TYPE_DAN     => $single
        ];
        return $card_types;
    }

    /**
     * 找出火箭及剩余手牌
     * @param $pokers
     * @return array
     */
    public function getRocket($pokers){
        if(in_array(78,$pokers) && in_array(79,$pokers)){
            foreach ($pokers as $k=>$v){
                if(in_array($v,[78,79])){
                    unset($pokers[$k]);
                }
            }
            $arr = ['rocket'=>[78,79],'left'=>$this->sortCardByGrade($pokers)];
        }else{
            $arr = ['rocket'=>null,'left'=>$this->sortCardByGrade($pokers)];
        }
        return $arr;
    }

    /**
     * 获取所有炸弹
     * @param $pokers
     * @return array
     */
    public function getBooms($pokers){
        $boom_arr  = [];
        for($i=0;$i<count($pokers);$i++){
            $com_val  = $pokers[$i];
            $boom[]   = $pokers[$i];
            for($j=$i+1; $j<(count($pokers));$j++){
                $com_v = $this->getModVal($com_val);
                $j_v   = $this->getModVal($pokers[$j]);
                if($com_v == $j_v){
                    $com_val  = $pokers[$j];
                    array_push($boom,$pokers[$j]);
                    if(count($boom) >= 4){
                        $left_pokers = $this->sortCardByGrade(array_diff($pokers,$boom));
                        array_push($boom_arr,$boom);
                        break;
                    }
                }
            }
            unset($boom);
        }
        if(isset($left_pokers) && (count($left_pokers) >= 4)){
            $this->getAllTripleArr($left_pokers);
        }
        return $boom_arr;
    }

    /**
     * 取出最小顺子
     * @param $pokers
     * @return  array
     */
    public function getAllShunZi($pokers){
        $total_arr  = [];
        for($i=0;$i<count($pokers);$i++){
            $com_val  = $pokers[$i];
            $sz_arr[] = $pokers[$i];
            for($j = $i+1;$j < (count($pokers)); $j++){
                $com_v = $this->getModVal($com_val);
                $j_v   = $this->getModVal($pokers[$j]);
                // 顺子不连2
                if(($com_v+1 == $j_v) && (!in_array($pokers[$j],[13,29,45,61]))){
                    $com_val  = $pokers[$j];
                    array_push($sz_arr,$pokers[$j]);
                    if(count($sz_arr) >= 5){
                        $left_pokers = $this->sortCardByGrade(array_diff($pokers,$sz_arr));
                        array_push($total_arr,$sz_arr);
                        break 2;
                    }
                }
            }
            unset($sz_arr);
        }
        if(isset($left_pokers) && (count($left_pokers) >= 5)){
            $this->getAllShunZi($left_pokers);
        }
        return $total_arr;
    }

    /**
     * 获取剩余手牌
     * @param $arr
     * @param $pokers
     * @return array
     */
    public function getLeftCards($arr,$pokers){
        $cards = [];
        foreach ($arr as $k=>$v){
            if(is_array($v)){
                if(!empty($v)){
                    foreach ($v as $vv){
                        $cards[] = $vv;
                    }
                }
            }else{
                $cards[] = $v;
            }
        }
        $lefts = array_diff($pokers,$cards);
        if(!empty($lefts)){
            return $this->sortCardByGrade($lefts);
        }else{
            return [];
        }
    }

    /**
     * 扩展顺子并返回新的顺子和剩余手牌
     * @param $sz_arr
     * @param $left_cards
     * @return mixed
     */
    public function extStraightArr($sz_arr,$left_cards){
        $new_sz_arr = [];
        $new_left   = [];
        foreach ($sz_arr as $k=>$v){
            $res = $this->extShunZi($v,$left_cards);
            $new_sz_arr[] = $res['sz'];
            $new_left     = $res['left'];
        }
        $con['new_sz'] = $new_sz_arr;
        $con['left']   = $new_left;
        return $con;
    }

    /**
     * 找出所有三张
     * @param $pokers
     * @return array
     */
    public function getAllTripleArr($pokers){
        $triple_arr  = [];
        for($i=0;$i<count($pokers);$i++){
            $com_val  = $pokers[$i];
            $triple[] = $pokers[$i];
            for($j=$i+1; $j<(count($pokers));$j++){
                $com_v = $this->getModVal($com_val);
                $j_v   = $this->getModVal($pokers[$j]);
                if($com_v == $j_v){
                    $com_val  = $pokers[$j];
                    array_push($triple,$pokers[$j]);
                    if(count($triple) >= 3){
                        $left_pokers = $this->sortCardByGrade(array_diff($pokers,$triple));
                        array_push($triple_arr,$triple);
                        break;
                    }
                }
            }
            unset($triple);
        }
        if(isset($left_pokers) && (count($left_pokers) >= 3)){
            $this->getAllTripleArr($left_pokers);
        }
        return $triple_arr;
    }

    /**
     * 找出对子
     * @param $pokers
     * @return array
     */
    public function getDoubleArr($pokers){
        $double_arr  = [];
        for($i=0;$i<count($pokers);$i++){
            $com_val  = $pokers[$i];
            $double[] = $pokers[$i];
            for($j=$i+1; $j<(count($pokers));$j++){
                $com_v = $this->getModVal($com_val);
                $j_v   = $this->getModVal($pokers[$j]);
                if($com_v == $j_v){
                    $com_val  = $pokers[$j];
                    array_push($double,$pokers[$j]);
                    if(count($double) >= 2){
                        $left_pokers = $this->sortCardByGrade(array_diff($pokers,$double));
                        array_push($double_arr,$double);
                        break;
                    }
                }
            }
            unset($double);
        }
        if(isset($left_pokers) && (count($left_pokers) >= 2)){
            $this->getAllTripleArr($left_pokers);
        }
        return $double_arr;
    }

    /**
     * 扩展顺子
     * @param $sz
     * @param $left_cards
     * @return mixed
     */
    protected function extShunZi($sz,$left_cards){
        $last_sz   = end($sz);
        $ext = [];
        $com_data = $last_sz;
        for($i=0;$i<count($left_cards);$i++){
            $c_val = $this->getModVal($com_data);
            $i_val = $this->getModVal($left_cards[$i]);
            // 顺子不连2
            if(($c_val+1 == $i_val) && !in_array($left_cards[$i],[13,29,45,61])) {
                array_push($ext, $left_cards[$i]);
                $com_data = $left_cards[$i];
            }
        }
        // 组装新顺子
        $res['sz']   = $sz;
        $res['left'] = $left_cards;
        if(!empty($ext)){
            $first_ext = $this->getModVal($ext[0]);
            if(($last_sz+1) == $first_ext){
                // 如果连接的上
                foreach ($ext as $kk=>$vv){
                    $sz[] = $vv;
                }
                $res['sz']   = $this->sortCardByGrade($sz);
                $lft = array_diff($left_cards,$ext);
                if(empty($lft)){
                    $res['left'] = null;
                }else{
                    $res['left'] = $this->sortCardByGrade($lft);
                }
            }
        }
        return $res;
    }

    /**
     * 最值进行取模运算， 获取到牌的值
     * @param $val
     * @return int
     */
    protected function getModVal($val)
    {
        return $val % 16;
    }

    /**
     * 对手牌进行排序处理
     * @param array $card
     * @return array
     */
    public function sortCardByGrade($card = array())
    {
        //牌进行排序
        $new_card = array();
        foreach ($card as $v) {
            $new_card[$v] = $this->getModVal($v);
        }
        //对数组按值排序, 并保留键值
        asort($new_card);
        $card = array();
        foreach ($new_card as $k => $v) {
            $card[] = $k;
        }
        return $card;
    }

    /**
     * 检查炸弹出牌
     * @param $prev_card
     * @param $curr_cards
     * @return array
     */
    public function ableZhaDan($prev_card,$curr_cards){
        $cards = ['code'=>0,'data'=>[]];
        if(!empty($curr_cards)){
            foreach ($curr_cards as $k=>$v){
                if($this->getModVal($v[0]) > $this->getModVal($prev_card[0])){
                    $cards = ['code'=>1,'data'=>$v];
                    break;
                }
            }
        }
        return $cards;
    }

    /**
     * 检查顺子出牌
     * @param $prev_card
     * @param $curr_cards
     * @return array
     */
    public function ableShunZi($prev_card,$curr_cards){
        $cards = ['code'=>0,'data'=>[]];
        if(!empty($curr_cards)){
            foreach ($curr_cards as $k=>$v){
                $my_cnt    = count($v);
                $prev_cnt  = count($prev_card);
                if(($my_cnt == $prev_cnt) && ($this->getModVal($v[0]) > $this->getModVal($prev_card[0]))){
                    $cards = ['code'=>1,'data'=>$v];
                    break;
                }
            }
        }
        return $cards;
    }

    /**
     * 检查三带出牌
     * @param $pre_type
     * @param $prev_card
     * @param $curr_cards
     * @return array
     */
    public function ableSanDai($pre_type,$prev_card,$curr_cards){
        $cards = ['code'=>0,'data'=>[]];
        if(!empty($curr_cards[3])){
            if($pre_type == 3){
                // 三张不带
                foreach ($curr_cards[3] as $k=>$v){
                    if($this->getModVal($v[0]) > $this->getModVal($prev_card[0])){
                        $cards = ['code'=>1,'data'=>$v];
                        break;
                    }
                }
            }elseif($pre_type == 4){
                // 三代一
                if(!empty($curr_cards[1])){
                    $single = $curr_cards[1][0];
                }elseif(!empty($curr_cards[2])){
                    $single = $curr_cards[2][0][0];
                }else{
                    $single = null;
                }
                if(!empty($single)){
                    foreach ($curr_cards[3] as $k=>$v){
                        if($this->getModVal($v[1]) > $this->getModVal($prev_card[1])){
                            array_push($v,$single);
                            $cards = ['code'=>1,'data'=>$v];
                            break;
                        }
                    }
                }
            }elseif($pre_type == 5){
                // 三代一对
                $double = [];
                if(!empty($curr_cards[2])){
                    $double = $curr_cards[2][0][0];
                }
                if(!empty($double)){
                    foreach ($curr_cards[3] as $k=>$v){
                        if($this->getModVal($v[2]) > $this->getModVal($prev_card[2])){
                            $arr =array_merge($v,$double);
                            $cards = ['code'=>1,'data'=>$arr];
                            break;
                        }
                    }
                }
            }
        }
        return $cards;
    }


    /**
     * 检查对子出牌
     * @param $prev_card
     * @param $curr_cards
     * @return array
     */
    public function ableDuiZi($prev_card,$curr_cards){
        $cards = ['code'=>0,'data'=>[]];
        if(!empty($curr_cards)){
            foreach ($curr_cards as $k=>$v){
                $my_cnt    = count($v);
                $prev_cnt  = count($prev_card);
                if(($my_cnt == $prev_cnt) && ($this->getModVal($v[0]) > $this->getModVal($prev_card[0]))){
                    $cards = ['code'=>1,'data'=>$v];
                    break;
                }
            }
        }
        return $cards;
    }

    /**
     * 检查单张出牌
     * @param $prev_card
     * @param $curr_cards
     * @return array
     */
    public function ableDan($prev_card,$curr_cards){
        $cards = ['code'=>0,'data'=>[]];
        if(!empty($curr_cards)){
            foreach ($curr_cards as $k=>$v){
                if($this->getModVal($v) > $this->getModVal($prev_card[0])){
                    $cards = ['code'=>1,'data'=>[$v]];
                    break;
                }
            }
        }
        return $cards;
    }
}